package projeto;

import grafoS.*;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToolBar;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.text.Font;
import javafx.stage.FileChooser;
import java.lang.reflect.Method;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.Event;
import javafx.scene.control.Menu;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import lerFormatos.LerArquivo;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * Gcol is a program to help users to learn a little about graph coloring, in
 * this software, you can learn some coloring algorithms, and add your own
 * algorithm for coloring.You can also learn BFS and DFS search. This tool, also
 * support the .col format from DIMACS (Center for Discrete Mathematics and
 * Theoretical Computer Science), so you can import a big graph and use all the
 * algorithms. Copyright (C) <2015> Clóvis Daniel Souza Silva, Samuel Silva de
 * Souza, Professor Leonardo Sampaio Rocha.
 * 
* This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
* This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
* You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 * 
 * contact: projetoGrafos@gmail.com
 */
/**
 * @author Samuel
 * @author Daniel
 */
/**
 * Class where we create the interface.
 */
public class Controlev2 implements Initializable {

    private int cor[];
    private ArrayList<Integer> nVertices = new ArrayList<>();
    private int t;
    private int ind; // guarda o inteiro de um vertice para um drag...
    private ArrayList<Line> arestasChegando; // lista para procura de arestas...
    private ArrayList<Line> arestasSaindo;// lista para procura de arestas...
    private ArrayList<ArrayList<Circle>> vertices = new ArrayList<>();
    private ArrayList<ArrayList<Label>> listaLabel = new ArrayList<>();
    private ArrayList<ArrayList<Line>> arestas = new ArrayList<>();
    private ArrayList<Tab> tabs = new ArrayList<Tab>();
    private ArrayList<Integer> permissaoTab = new ArrayList<>(); //Para otimizar o codigo trocar o valor de int permissao tado vez que mudarmos a Tab
    private ArrayList<String> stringConsole = new ArrayList<>();
    private ArrayList<Graph> matrizAdjacencia = new ArrayList<>();
    private ArrayList<GraphList> listaAdjacencia = new ArrayList<>();
    private ArrayList<ArrayList<Label>> listacores = new ArrayList<>();
    private ArrayList<File> fl = new ArrayList<>();
    private double raio = 15;
    private double inicioArestaX = 0, inicioArestaY = 0, fimArestaX = 0, fimArestaY = 0;
    private int permissao = 0;
    private int nalgoritmo;
    private ArrayList<Boolean> dimacsFile = new ArrayList<>();
    @FXML
    private javafx.scene.control.TextArea console;
    @FXML
    private AnchorPane ap;
    @FXML
    private Pane canv;
    @FXML
    private ToggleButton mouse, move, apagar;
    @FXML
    private MenuItem salvar, abrir, abrirD, deletar, novo, bfs, dfs, gerarMatriz, gerarLista;
    @FXML
    Menu menucol;
    @FXML
    MenuBar barraDeMenu;
    @FXML
    private ToolBar toolbar;
    @FXML
    private TabPane tabPane;
    @FXML
    private Tab tab1;
    @FXML
    private Button adicao;
    @FXML
    private MenuItem about;

    public void initialize(URL url, ResourceBundle bundle) {
        try {
            String s = System.getProperty("user.dir").replaceAll("\\\\", "/");
            File arquivo;
            if (s.contains("dist")) {
                arquivo = new File(s.replace("dist", "src/Algoritmos"));
            } else {
                arquivo = new File(s + "/src/Algoritmos");
            }

            File[] files = arquivo.listFiles();
            int cont = 0;
            console.appendText("Loaded Classes :\n");
            for (int i = 0; i < files.length; i++) {
                if (files[i].getName().endsWith(".java") && !files[i].getName().contains("Algorithm")) {
                    fl.add(files[i]);
                    String nomedaclasse[] = files[i].getName().split(".java");
                    MenuItem item = new MenuItem(nomedaclasse[0]);
                    console.appendText(nomedaclasse[0] + "\n");
                    item.setOnAction(this::handleAlgoritmos);
                    item.setId(Integer.toString(cont));
                    cont++;
                    menucol.getItems().add(item);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        console.end();

        tabPane.getStyleClass().add("floating");
        tab1.setText("Graph 1");
        nVertices.add(0);
        ArrayList<Circle> listaVertices = new ArrayList<>();
        ArrayList<Label> listaLabels = new ArrayList<>();
        ArrayList<Line> listaArestas = new ArrayList<>();
        ArrayList<Label> listacor = new ArrayList<>();
        stringConsole.add("");
        vertices.add(listaVertices);
        listaLabel.add(listaLabels);
        arestas.add(listaArestas);
        listacores.add(listacor);
        matrizAdjacencia.add(null);
        listaAdjacencia.add(null);
        permissaoTab.add(0);
        canv.setOnMouseClicked(this::handleP);
        adiciornarTabs();
        dimacsFile.add(false);
        About();

    }

    @FXML
    private void handleTabPane(MouseEvent arg0) {
        t = tabPane.getSelectionModel().getSelectedIndex();
        if (t != -1) {
            console.setText(stringConsole.get(t));
        }
        console.end();
    }

    private void About() {
        about.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                console.setText("    Gcol is a program to help users to learn a little about graph coloring,\n"
                        + "    in this software, you can learn some coloring algorithms, and add your\n"
                        + "    own algorithm for coloring.You can also learn BFS and DFS search.\n"
                        + "    This tool, also support the .col format from DIMACS(Center for Discrete Mathematics and Theoretical Computer Science), so you can import a big"
                        + " graph and use all the algorithms. \n"
                        + "    Copyright (C) <2015>  Clóvis Daniel Souza Silva, Samuel Silva  de Souza, Professor Leonardo Sampaio Rocha.\n"
                        + "\n"
                        + "    This program is free software: you can redistribute it and/or modify\n"
                        + "    it under the terms of the GNU General Public License as published by\n"
                        + "    the Free Software Foundation, either version 3 of the License, or\n"
                        + "    (at your option) any later version.\n"
                        + "\n"
                        + "    This program is distributed in the hope that it will be useful,\n"
                        + "    but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
                        + "    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
                        + "    GNU General Public License for more details.\n"
                        + "\n"
                        + "    You should have received a copy of the GNU General Public License\n"
                        + "    along with this program.  If not, see <http://www.gnu.org/licenses/>.");
            }
        });
    }

    private void adiciornarTabs() {
        adicao.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent arg0) {
                if (t == -1) {
                    t = 0;
                }
                Tab tab = new Tab();
                Pane painel = new Pane();
                painel.setStyle("-fx-background-color: white");
                carregarPane(painel, tab);
                tab.setContent(painel);
                tabPane.setStyle("-fx-background-color: white");
                tabPane.getTabs().add(tab);
                tab.setText("Graph " + tabPane.getTabs().size());
                nVertices.add(0);
                permissaoTab.add(0);
                ArrayList<Circle> listaVertices = new ArrayList<>();
                ArrayList<Label> listaLabels = new ArrayList<>();
                ArrayList<Line> listaArestas = new ArrayList<>();
                ArrayList<Label> listacor = new ArrayList<>();
                stringConsole.add("");
                vertices.add(listaVertices);
                listaLabel.add(listaLabels);
                arestas.add(listaArestas);
                listacores.add(listacor);
                dimacsFile.add(false);
                matrizAdjacencia.add(null);
                listaAdjacencia.add(null);

            }
        });
        novo.setOnAction(new EventHandler<ActionEvent>() {
            public void handle(ActionEvent arg0) {
                if (t == -1) {
                    t = 0;
                }
                Tab tab = new Tab();
                Pane painel = new Pane();
                painel.setStyle("-fx-background-color: white");
                carregarPane(painel, tab);
                tab.setContent(painel);
                tabPane.setStyle("-fx-background-color: white");
                tabPane.getTabs().add(tab);
                tab.setText("Graph " + tabPane.getTabs().size());
                nVertices.add(0);
                permissaoTab.add(0);
                ArrayList<Circle> listaVertices = new ArrayList<>();
                ArrayList<Label> listaLabels = new ArrayList<>();
                ArrayList<Line> listaArestas = new ArrayList<>();
                ArrayList<Label> listacor = new ArrayList<>();
                stringConsole.add("");
                vertices.add(listaVertices);
                listaLabel.add(listaLabels);
                arestas.add(listaArestas);
                listacores.add(listacor);
                dimacsFile.add(false);
                if (t == -1) {
                    t = 0;
                }
                matrizAdjacencia.add(null);
                listaAdjacencia.add(null);

            }
        });

    }

    private void carregarPane(Pane painel, Tab tab) {
        painel.setOnMouseClicked(this::handleP);
        painel.setOnMousePressed(this::handlePanelPressed);
        painel.setOnMouseReleased(this::handlePanelReleased);
        painel.setOnMouseDragged(this::handlePanelDragged);
        tab.setOnCloseRequest(this::fecharAba);
        tab.setOnClosed(this::fecharAbaDepois);

    }

    @FXML
    private void fecharAba(Event arg0) {
        t = tabPane.getSelectionModel().getSelectedIndex();
        vertices.remove(t);
        listaLabel.remove(t);
        arestas.remove(t);
        nVertices.remove(t);
        listacores.remove(t);
        permissaoTab.remove(t);
        matrizAdjacencia.set(t, null);
        listaAdjacencia.set(t, null);
        stringConsole.remove(t);
        dimacsFile.remove(t);
    }

    @FXML
    private void fecharAbaDepois(Event arg0) {
        for (int i = 0; i < tabPane.getTabs().size(); i++) {
            if (tabPane.getTabs().get(i).getText().contains("Graph")) {
                tabPane.getTabs().get(i).setText("Graph " + (i + 1));
            }
        }
    }

    @FXML
    private void handleDeletar(ActionEvent arg) {
        ((Pane) tabPane.getTabs().get(t).getContent()).getChildren().clear();
        arestas.get(t).clear();
        vertices.get(t).clear();
        listaLabel.get(t).clear();
        nVertices.set(t, 0);
        console.clear();
    }

    @FXML
    private void handleRenomear(ActionEvent arg) {
        String nome = JOptionPane.showInputDialog(null, "What is the new name?", "Rename:", JOptionPane.QUESTION_MESSAGE);
        tabPane.getTabs().get(t).setText(nome);

    }

    @FXML
    private void handleSalvar(ActionEvent arg) {
        try {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("Save Graph");
            fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("XML", "*.xml"));
            File f = fileChooser.showSaveDialog(null);
            if (f == null) {
                return;
            }
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
            Document doc = docBuilder.newDocument();
            Element grafo = doc.createElement("Graph");
            doc.appendChild(grafo);

            for (int i = 0; i < vertices.get(t).size(); i++) {
                Element vertice = doc.createElement("Vertex");
                vertice.setAttribute("id", String.valueOf(i + 1));
                vertice.setAttribute("LayoutX", String.valueOf(vertices.get(t).get(i).getLayoutX()));
                vertice.setAttribute("LayoutY", String.valueOf(vertices.get(t).get(i).getLayoutY()));
                grafo.appendChild(vertice);
            }

            for (int i = 0; i < arestas.get(t).size(); i++) {
                Element aresta = doc.createElement("Edge");
                aresta.setAttribute("StarX", String.valueOf(arestas.get(t).get(i).getStartX()));
                aresta.setAttribute("StartY", String.valueOf(arestas.get(t).get(i).getStartY()));
                aresta.setAttribute("EndX", String.valueOf(arestas.get(t).get(i).getEndX()));
                aresta.setAttribute("EndY", String.valueOf(arestas.get(t).get(i).getEndY()));
                grafo.appendChild(aresta);
            }
            Element matriz = doc.createElement("AdjacencyMatrix");
            gerarMatrizAdjacencia();
            matriz.appendChild(doc.createTextNode(matrizAdjacencia.get(t).returnGrafo(console, stringConsole, t)));
            grafo.appendChild(matriz);
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource source = new DOMSource(doc);
            StreamResult result = new StreamResult(f);
            transformer.transform(source, result);
            console.appendText("File Saved!\n");
            console.end();
            stringConsole.set(t, console.getText());

        } catch (ParserConfigurationException pc) {
            pc.printStackTrace();
        } catch (TransformerException tfe) {
            tfe.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @FXML
    private void handleAbrir(ActionEvent arg) {
        try {
            FileChooser fileChooser = new FileChooser();
            fileChooser.setTitle("Open XML");
            fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("XML", "*.xml"));
            File f = fileChooser.showOpenDialog(null);
            if (f != null) {
                DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
                Document doc = dBuilder.parse(f);
                NodeList nListVertice = doc.getElementsByTagName("Vertex");
                NodeList nListAresta = doc.getElementsByTagName("Edge");
                ((Pane) tabPane.getTabs().get(t).getContent()).getChildren().clear();
                arestas.get(t).clear();
                vertices.get(t).clear();
                listaLabel.get(t).clear();
                for (int i = 0; i < nListAresta.getLength(); i++) {
                    Element aresta = (Element) nListAresta.item(i);
                    Line linha = new Line();
                    linha.setStartX(Double.parseDouble(aresta.getAttribute("StarX")));
                    linha.setStartY(Double.parseDouble(aresta.getAttribute("StartY")));
                    linha.setEndX(Double.parseDouble(aresta.getAttribute("EndX")));
                    linha.setEndY(Double.parseDouble(aresta.getAttribute("EndY")));
                    arestas.get(t).add(linha);
                    ((Pane) tabPane.getTabs().get(t).getContent()).getChildren().addAll(linha);
                }

                for (int i = 0; i < nListVertice.getLength(); i++) {
                    Element vertice = (Element) nListVertice.item(i);
                    Circle circle = new Circle();
                    circle.setStroke(Color.BLACK);
                    circle.setStrokeWidth(2);
                    circle.setFill(Color.WHITE);
                    circle.setLayoutX(Double.parseDouble(vertice.getAttribute("LayoutX")));
                    circle.setLayoutY(Double.parseDouble(vertice.getAttribute("LayoutY")));
                    circle.setCenterX(0);
                    circle.setCenterY(0);
                    circle.setRadius(raio);
                    circle.setId(vertice.getAttribute("id"));
                    Label numero = new Label();
                    numero.setText(vertice.getAttribute("id"));
                    numero.setLayoutX(Double.parseDouble(vertice.getAttribute("LayoutX")) - 4);
                    numero.setLayoutY(Double.parseDouble(vertice.getAttribute("LayoutY")) - 11);
                    numero.setFont(Font.font("", 18));
                    vertices.get(t).add(circle);
                    cor = new int[vertices.get(t).size()];
                    listaLabel.get(t).add(numero);
                    ((Pane) tabPane.getTabs().get(t).getContent()).getChildren().addAll(circle, numero);
                }

                nVertices.add(t, Integer.parseInt(vertices.get(t).get((vertices.get(t).size()) - 1).getId()));
            }

        } catch (ParserConfigurationException pc) {
            pc.printStackTrace();
        } catch (Exception e) {
        }

    }

    @FXML
    private void handleAbrirD(ActionEvent arg0) {
        int tabExecuntando = tabPane.getSelectionModel().getSelectedIndex();
        FileChooser fileChooser = new FileChooser();
        fileChooser.setTitle("Open DIMACS");
        fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("COL", "*.col"));
        ((Pane) tabPane.getTabs().get(t).getContent()).getChildren().clear();
        arestas.get(t).clear();
        vertices.get(t).clear();
        listaLabel.get(t).clear();
        File f = fileChooser.showOpenDialog(null);
        if (f == null) {
            return;
        }
        LerArquivo ler = new LerArquivo();
        matrizAdjacencia.set(t, ler.lerDIMACS(f));
        Tranformador transfomador = new Tranformador();
        listaAdjacencia.set(t, transfomador.transformaAdj(matrizAdjacencia.get(t)));
        nVertices.set(t, matrizAdjacencia.get(t).getN());
        cor = new int[nVertices.get(t)];
        Pane p = (Pane) tabPane.getTabs().get(t).getContent();
        //TODO tabPane.getTabs().get(t).getContent().setDisable(true);
        int[] vA = ler.read('p', null, f); // vertices e arestas.
        Integer vert = vA[0];
        Integer arest = vA[1];
//

        if (tabPane.getSelectionModel().getSelectedIndex() == tabExecuntando) {
            console.appendText("File Opened!!\n"
                    + "Total of Vertices: " + vert.toString() + "\n"
                    + "Total of Edges: " + arest.toString() + "\n");
            console.end();
        }
        stringConsole.set(tabExecuntando, stringConsole.get(tabExecuntando) + "File Opened!!\n"
                + "Total of Vertices: " + vert.toString() + "\n"
                + "Total of Edges: " + arest.toString() + "\n");
        dimacsFile.set(tabExecuntando, true);
    }

    @FXML
    private void handleP(MouseEvent arg0) {
        if (dimacsFile.get(t) == false && !mouse.isSelected() && !move.isSelected() && !apagar.isSelected() && permissaoTab.get(tabPane.getSelectionModel().getSelectedIndex()) == 0) {
            Pane p = (Pane) tabPane.getTabs().get(t).getContent();
            nVertices.set(t, nVertices.get(t) + 1);
            Circle circle = new Circle();
            circle.setStroke(Color.BLACK);
            circle.setStrokeWidth(2);
            circle.setFill(Color.WHITE);
            circle.setLayoutX(arg0.getX());
            circle.setLayoutY(arg0.getY());
            circle.setCenterX(0);
            circle.setCenterY(0);
            circle.setRadius(raio);
            circle.setId(nVertices.get(t).toString());
            Label numero = new Label();
            numero.setText(nVertices.get(t).toString());
            numero.setLayoutX(arg0.getX() - 4);
            numero.setLayoutY(arg0.getY() - 11);
            numero.setFont(Font.font("", 18));
            vertices.get(t).add(circle);
            //arestas.get(t).add("");
            cor = new int[vertices.get(t).size()];
            listaLabel.get(t).add(numero);
            p.getChildren().addAll(circle, numero);

        }
        if (apagar.isSelected()) {
            int ind = getIndiceVertice(arg0.getX(), arg0.getY());
            if (ind != -1) {
                arestasChegando = getArestasChegando(vertices.get(t).get(ind));
                arestasSaindo = getArestasSaindo(vertices.get(t).get(ind));

                for (int i = 0; i < arestas.get(t).size(); i++) {
                    for (int j = 0; j < arestasChegando.size(); j++) {
                        if (arestas.get(t).get(i).equals(arestasChegando.get(j))) {
                            ((Pane) tabPane.getTabs().get(t).getContent()).
                                    getChildren().remove(arestas.get(t).get(i));
                            arestas.get(t).remove(arestasChegando.get(j));

                        }
                    }
                }

                for (int i = 0; i < arestas.get(t).size(); i++) {
                    for (int j = 0; j < arestasSaindo.size(); j++) {
                        if (arestas.get(t).get(i).equals(arestasSaindo.get(j))) {
                            ((Pane) tabPane.getTabs().get(t).getContent()).
                                    getChildren().remove(arestas.get(t).get(i));
                            arestas.get(t).remove(arestasSaindo.get(j));

                        }
                    }
                }

                Integer aux = 0;
                ((Pane) tabPane.getTabs().get(t).getContent()).getChildren().remove(listaLabel.get(t).get(ind));
                ((Pane) tabPane.getTabs().get(t).getContent()).getChildren().remove(vertices.get(t).get(ind));
                listaLabel.get(t).remove(ind);
                vertices.get(t).remove(ind);

                if (listaLabel.get(t).size() >= ind + 2) {
                    for (int i = ind + 1; i < listaLabel.get(t).size(); i++) {
                        aux = i;
                        listaLabel.get(t).get(i).setText(aux.toString());
                    }
                }

                nVertices.set(t, nVertices.get(t) - 1);
            }
        }

        if (permissaoTab.get(t) == 1 && dimacsFile.get(t) == false) {
            int vertice = getIndiceVertice(arg0.getX(), arg0.getY());
            if (vertice != -1) {
                tabPane.getTabs().get(t).getContent().setDisable(true);
                gerarMatrizAdjacencia();
                Runnable b = new BuscaLargura(vertice, matrizAdjacencia.get(t), tabPane,
                        stringConsole, permissaoTab, vertices, console, nVertices, t);
                Thread t = new Thread(b);
                t.start();
            } else {
                permissaoTab.set(t, 0);
            }
        }

        if (permissaoTab.get(t) == 2 && dimacsFile.get(t) == false) {
            int vertice = getIndiceVertice(arg0.getX(), arg0.getY());
            if (vertice != -1) {
                tabPane.getTabs().get(t).getContent().setDisable(true);
                gerarListaAdjacencia();
                BuscaProfundidade b = new BuscaProfundidade(vertice, listaAdjacencia.get(t), tabPane, stringConsole,
                        permissaoTab, vertices, console, dimacsFile.get(t));
                b.start();

            } else {
                permissaoTab.set(t, 0);
            }

        }
        if (permissaoTab.get(t) == 3) {
            int tabExecuntando = tabPane.getSelectionModel().getSelectedIndex();
            int vertice = getIndiceVertice(arg0.getX(), arg0.getY());
            int cont = 0;
            if (vertice != -1) {
                try {
                    String nomedaclasse[] = fl.get(nalgoritmo).getName().split(".java");
                    ClassLoader cl = Controlev2.class.getClassLoader();
                    Class[] types = {Graph.class, int.class};
                    Method b = cl.loadClass("Algoritmos." + nomedaclasse[0]).getMethod("ReturnColor", types);
                    Object algoritmo = cl.loadClass("Algoritmos." + nomedaclasse[0]).newInstance();
                    int resulcor[] = (int[]) b.invoke(algoritmo, matrizAdjacencia.get(t), vertice);
                    int melhorcor = -1;

                    if (listacores.get(tabExecuntando).size() == vertices.get(tabExecuntando).size()) {
                        for (int i = 0; i < vertices.get(tabExecuntando).size(); i++) {
                            Label coratual = listacores.get(tabExecuntando).get(i);
                            coratual.setText(String.valueOf(resulcor[i]));
                            coratual.setLayoutX(vertices.get(tabExecuntando).get(i).getLayoutX() + 15);
                            coratual.setLayoutY(vertices.get(tabExecuntando).get(i).getLayoutY() + 15);
                            if (melhorcor < resulcor[i]) {
                                melhorcor = resulcor[i];
                            }
                        }
                    } else {
                        for (int i = 0; i < vertices.get(tabExecuntando).size(); i++) {
                            listacores.get(tabExecuntando).add(new Label());
                            Label coratual = listacores.get(tabExecuntando).get(i);
                            coratual.setText(String.valueOf(resulcor[i]));
                            coratual.setLayoutX(vertices.get(tabExecuntando).get(i).getLayoutX() + 15);
                            coratual.setLayoutY(vertices.get(tabExecuntando).get(i).getLayoutY() + 15);
                            ((Pane) tabPane.getTabs().get(tabExecuntando).getContent()).getChildren()
                                    .add(coratual);
                            if (melhorcor < resulcor[i]) {
                                melhorcor = resulcor[i];
                            }
                        }
                    }

                    if (tabPane.getSelectionModel().getSelectedIndex() == tabExecuntando) {
                        String append = "The number of colors used in the graph: " + melhorcor + "\n";
                        for (int i = 0; i < resulcor.length; i++) {
                            append += "Vertex " + (i + 1) + ": " + listacores.get(tabExecuntando).
                                    get(i).getText() + "\n";

                        }
                        stringConsole.set(tabExecuntando, stringConsole.get(tabExecuntando) + append + "\n");

                    } else {
                        String append = stringConsole.get(tabExecuntando) + "The number of colors used in the graph: " + melhorcor + "\n";
                        for (int i = 0; i < resulcor.length; i++) {
                            append += "Vertex " + (i + 1) + ": " + listacores.get(tabExecuntando).
                                    get(i).getText() + "\n";;
                        }
                        stringConsole.set(tabExecuntando, append + "\n");

                    }
                    stringConsole.set(tabExecuntando, stringConsole.get(tabExecuntando)
                            + "Click in the canvas to clean the colors. \n");
                    console.setText(stringConsole.get(tabExecuntando));
                    console.end();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                toWhite(tabExecuntando);
                permissaoTab.set(tabExecuntando, 0);

            }

        }
        if (permissaoTab.get(t) == 4) {
            toWhite(t);
            permissaoTab.set(t, 0);
        }

    }

    @FXML
    private void handleAlgoritmos(ActionEvent arg) { // Caso os algoritmos somente retornem um vetor de cores.
        //boolean teste = true;
        if (dimacsFile.get(t) == false && !vertices.get(t).isEmpty()) // Exessão para o dimacs, se nao gerar matriz, gera matriz em branca, pq não há desenho.
        {
            gerarMatrizAdjacencia();
        }
        permissaoTab.set(t, 3);
        apagar.setSelected(false);
        move.setSelected(false);
        mouse.setSelected(false);
        int tabExecuntando = t;
        nalgoritmo = Integer.parseInt(((MenuItem) arg.getSource()).getId());

        try {
            String nomedaclasse[] = fl.get(nalgoritmo).getName().split(".java");
            ClassLoader cl = Controlev2.class.getClassLoader();
            Class[] types = {Graph.class};
            Method[] b = cl.loadClass("Algoritmos." + nomedaclasse[0]).getMethods();
            int posição = 0;
            for (int i = 0; i < b.length; i++) {
                if (b[i].toGenericString().contains("Algoritmos." + nomedaclasse[0] + "." + "ReturnColor")) {
                    posição = i;

                }
            }
            if (b[posição].getParameterCount() == 1) {
                permissaoTab.set(t, 4);
                Object algoritmo = cl.loadClass("Algoritmos." + nomedaclasse[0]).newInstance();
                int resulcor[] = (int[]) b[posição].invoke(algoritmo, matrizAdjacencia.get(t));
                int melhorcor = -1;

                for (int i = 0; i < resulcor.length; i++) {
                    if (dimacsFile.get(tabExecuntando) == false) {
                        listacores.get(tabExecuntando).add(new Label());
                        Label coratual = listacores.get(tabExecuntando).get(i);
                        coratual.setText(String.valueOf(resulcor[i]));
                        coratual.setLayoutX(vertices.get(tabExecuntando).get(i).getLayoutX() + 15);
                        coratual.setLayoutY(vertices.get(tabExecuntando).get(i).getLayoutY() + 15);
                        ((Pane) tabPane.getTabs().get(tabExecuntando).getContent()).getChildren()
                                .add(coratual);
                    }
                    if (melhorcor < resulcor[i]) {
                        melhorcor = resulcor[i];
                    }
                }

                if (tabPane.getSelectionModel().getSelectedIndex() == tabExecuntando) {
                    String append = "The number of colors used in the graph is: " + melhorcor + "\n";
                    for (int i = 0; i < resulcor.length; i++) {
                        append += "Vertex " + (i + 1) + ": " + resulcor[i] + "\n";

                    }
                    stringConsole.set(tabExecuntando, stringConsole.get(tabExecuntando) + append + "\n");
                    console.appendText(append + "\n");
                    console.end();
                } else {
                    String append = stringConsole.get(tabExecuntando) + "The number of colors used in the graph is: " + melhorcor + "\n";
                    for (int i = 0; i < resulcor.length; i++) {
                        append += "Vertex " + (i + 1) + ": " + resulcor[i] + "\n";
                    }
                    stringConsole.set(tabExecuntando, append + "\n");

                }
                stringConsole.set(tabExecuntando, stringConsole.get(tabExecuntando)
                        + "Click in the canvas to clean the colors \n");
                console.appendText(stringConsole.get(tabExecuntando));
                console.end();
            } else {
                apagar.setSelected(false);
                move.setSelected(false);
                mouse.setSelected(false);
                stringConsole.set(t, console.getText());

            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        if (permissaoTab.get(t) == 3 && dimacsFile.get(tabExecuntando) == true) {// Caso as algoritmos adicionados utilizem clique no grafo.
            Task tarefaCargaPg = new Task() {

                @Override
                protected String call() throws Exception {
                    Platform.runLater(() -> ap.setDisable(true));
                    return JOptionPane.showInputDialog("Choose the vertex to begin.");
                }

                @Override
                protected void succeeded() {
                    ap.setDisable(false);
                    String v = (String) getValue();
                    if (v == null) {
                        return;
                    }
                    int vertice = Integer.parseInt(v);
                    vertice = vertice - 1;
                    if (!(vertice < 0)) {//Pode entrar como 0 n ?
                        int tabExecuntando = tabPane.getSelectionModel().getSelectedIndex();
                        int cont = 0;
                        int error = 0;
                        if (vertice != -1) {
                            try {

                                String nomedaclasse[] = fl.get(nalgoritmo).getName().split(".java");
                                ClassLoader cl = Controlev2.class.getClassLoader();
                                Class[] types = {Graph.class, int.class};
                                Method b = cl.loadClass("Algoritmos." + nomedaclasse[0]).getMethod("ReturnColor", types);
                                Object algoritmo = cl.loadClass("Algoritmos." + nomedaclasse[0]).newInstance();
                                int resulcor[] = (int[]) b.invoke(algoritmo, matrizAdjacencia.get(t), vertice);

                                int melhorcor = -1;
                                for (int i = 0; i < resulcor.length; i++) {
                                    if (melhorcor < resulcor[i]) {
                                        melhorcor = resulcor[i];
                                    }
                                }
                                if (error == 0) {
                                    if (tabPane.getSelectionModel().getSelectedIndex() == tabExecuntando) {
                                        String append = "The numbers of colors used in the graph is: " + melhorcor + "\n";
                                        for (int i = 0; i < resulcor.length; i++) {
                                            append += "Vertex " + (i + 1) + ": " + resulcor[i] + "\n";

                                        }
                                        stringConsole.set(tabExecuntando, stringConsole.get(tabExecuntando) + append + "\n");

                                    } else {
                                        String append = stringConsole.get(tabExecuntando) + "The numbers of colors used in the graph is: " + melhorcor + "\n";
                                        for (int i = 0; i < resulcor.length; i++) {
                                            append += "Verte " + (i + 1) + ": " + resulcor[i] + "\n";;
                                        }
                                        stringConsole.set(tabExecuntando, append + "\n");
                                    }

                                }

                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        stringConsole.set(tabExecuntando, stringConsole.get(t)
                                + "Click in the canvas to clean the colors. \n");
                        console.setText(stringConsole.get(tabExecuntando));
                        console.end();
                        toWhite(tabPane.getSelectionModel().getSelectedIndex());
                        permissaoTab.set(tabPane.getSelectionModel().getSelectedIndex(), 0);

                    }
                }
            };

            Thread t = new Thread(tarefaCargaPg);
            t.setDaemon(true);
            t.start();

        } else {
            if (permissaoTab.get(t) == 3) {
                stringConsole.set(tabExecuntando, stringConsole.get(t)
                        + "Click in any vertex to begin!\n");
                console.setText(stringConsole.get(t));
                console.end();
            }
        }

    }

    @FXML
    private void handleBfs(ActionEvent arg) {
        int tabExecuntando = tabPane.getSelectionModel().getSelectedIndex();
        if (dimacsFile.get(tabExecuntando) == true) {
            Task tarefaCargaPg = new Task() {
                //int tabExecuntando = tabPane.getSelectionModel().getSelectedIndex();

                @Override
                protected String call() throws Exception {
                    Platform.runLater(() -> ap.setDisable(true));
                    return JOptionPane.showInputDialog("Choose the vertex to begin.");
                }

                @Override
                protected void succeeded() {
                    ap.setDisable(false);
                    String v = (String) getValue();
                    if (v == null) {
                        return;
                    }
                    int vertice = Integer.parseInt(v);
                    vertice = vertice - 1;
                    if (!(vertice <= 0)) {
                        tabPane.getTabs().get(t).getContent().setDisable(true);
                        Runnable b = new BuscaLargura(vertice, matrizAdjacencia.get(t), tabPane,
                                stringConsole, permissaoTab, null, console, nVertices, t);
                        Thread t = new Thread(b);
                        t.start();
                    } else {
                        JOptionPane.showMessageDialog(null, "Invalid Vertex!!", "ERROR", JOptionPane.ERROR_MESSAGE);
                    }
                }
            };

            Thread t = new Thread(tarefaCargaPg);
            t.setDaemon(true);
            t.start();
        } else {
            permissaoTab.set(tabExecuntando, 1);
            apagar.setSelected(false);
            move.setSelected(false);
            mouse.setSelected(false);
            console.appendText("Click on the vertex to begin.\n");
            console.end();
            stringConsole.set(tabExecuntando, console.getText());
        }
    }

    @FXML
    private void handleDfs(ActionEvent arg0) {
        if (dimacsFile.get(t) == true) {
            Task tarefaCargaPg = new Task() {
                //int tabExecuntando = tabPane.getSelectionModel().getSelectedIndex();

                @Override
                protected String call() throws Exception {
                    Platform.runLater(() -> ap.setDisable(true));
                    return JOptionPane.showInputDialog("Choose the vertex to begin.");
                }

                @Override
                protected void succeeded() {
                    ap.setDisable(false);
                    String v = (String) getValue();
                    if (v == null) {
                        return;
                    }
                    int vertice = Integer.parseInt(v);
                    vertice = vertice - 1;
                    if (!(vertice <= 0)) {
                        tabPane.getTabs().get(t).getContent().setDisable(true);
                        Runnable b = new BuscaProfundidade(vertice, listaAdjacencia.get(t), tabPane, stringConsole,
                                permissaoTab, vertices, console, dimacsFile.get(t));
                        Thread t = new Thread(b);
                        t.start();
                    } else {
                        JOptionPane.showMessageDialog(null, "Invalid Vertex!", "ERROR", JOptionPane.ERROR_MESSAGE);

                    }
                }
            };

            Thread t = new Thread(tarefaCargaPg);
            t.setDaemon(true);
            t.start();
        } else {
            int tabExecuntando = tabPane.getSelectionModel().getSelectedIndex();
            permissaoTab.set(tabExecuntando, 2);
            apagar.setSelected(false);
            move.setSelected(false);
            mouse.setSelected(false);
            console.appendText("Click on the vertex to begin.\n");
            console.end();
            stringConsole.set(tabExecuntando, console.getText());

        }
    }

    @FXML
    private void handlePanelPressed(MouseEvent arg) {
        if (mouse.isSelected() && permissaoTab.get(t) == 0) {
            inicioArestaX = arg.getX();
            inicioArestaY = arg.getY();
            int aux = getIndiceVertice(inicioArestaX, inicioArestaY);
            Line line = new Line();
            arestas.get(t).add(line);
            if (aux != -1) {

                line.setStartX(vertices.get(t).get(aux).getLayoutX());
                line.setStartY(vertices.get(t).get(aux).getLayoutY());
                line.setEndX(vertices.get(t).get(aux).getLayoutX());
                line.setEndY(vertices.get(t).get(aux).getLayoutY());
                ((Pane) tabPane.getTabs().get(t).getContent()).getChildren().addAll(line);
                vertices.get(t).get(aux).toFront();
                listaLabel.get(t).get(aux).toFront();
            }
        }
        if (move.isSelected() && permissaoTab.get(t) == 0) {
            ind = getIndiceVertice(arg.getX(), arg.getY());

            if (ind != -1) {
                arestasChegando = getArestasChegando(vertices.get(t).get(ind));
                arestasSaindo = getArestasSaindo(vertices.get(t).get(ind));
            }
        }
    }

    @FXML
    private void handlePanelReleased(MouseEvent arg) {
        if (mouse.isSelected() && permissaoTab.get(t) == 0) {
            fimArestaX = arg.getX();
            fimArestaY = arg.getY();
            int aux1 = getIndiceVertice(inicioArestaX, inicioArestaY);
            int aux2 = getIndiceVertice(fimArestaX, fimArestaY);
            boolean novaAresta = true;
            for (int i = 0; i < arestas.get(t).size(); i++) {
                if (aux2 != -1 && arestas.get(t).get(i).getEndX() == vertices.get(t).get(aux2).getLayoutX()
                        && arestas.get(t).get(i).getEndY() == vertices.get(t).get(aux2).getLayoutY()
                        && arestas.get(t).get(i).getStartX() == vertices.get(t).get(aux1).getLayoutX()
                        && arestas.get(t).get(i).getStartY() == vertices.get(t).get(aux1).getLayoutY()) {

                    novaAresta = false;
                }
            }
            if ((aux2 == -1) || (aux1 == aux2) || !novaAresta) {

                if (aux1 != -1) {
                    Line l = arestas.get(t).remove(arestas.get(t).size() - 1);
                    ((Pane) tabPane.getTabs().get(t).getContent()).getChildren().remove(l);
                }

            } else {
                if (aux1 != -1 && novaAresta) {
                    arestas.get(t).get(arestas.get(t).size() - 1).setEndX(vertices.get(t).get(aux2).getLayoutX());
                    arestas.get(t).get(arestas.get(t).size() - 1).setEndY(vertices.get(t).get(aux2).getLayoutY());
                    arestas.get(t).get(arestas.get(t).size() - 1).setId(String.valueOf(arestas.get(t).size() - 1));

                    vertices.get(t).get(aux2).toFront();
                    listaLabel.get(t).get(aux2).toFront();
                }
            }
        }
    }

    @FXML
    private void handlePanelDragged(MouseEvent arg) {
        if (move.isSelected() && permissaoTab.get(t) == 0) {
            if (ind != -1) {
                vertices.get(t).get(ind).setLayoutX(arg.getX());
                vertices.get(t).get(ind).setLayoutY(arg.getY());
                listaLabel.get(t).get(ind).setLayoutX(vertices.get(t).get(ind).getLayoutX() - 4);
                listaLabel.get(t).get(ind).setLayoutY(vertices.get(t).get(ind).getLayoutY() - 11);

                for (int i = 0; i < arestasChegando.size(); i++) {
                    arestasChegando.get(i).setEndX(arg.getX());
                    arestasChegando.get(i).setEndY(arg.getY());

                }
                for (int j = 0; j < arestasSaindo.size(); j++) {
                    arestasSaindo.get(j).setStartX(arg.getX());
                    arestasSaindo.get(j).setStartY(arg.getY());

                }
                vertices.get(t).get(ind).toFront();
                listaLabel.get(t).get(ind).toFront();
            }
        }

        if (mouse.isSelected() && permissaoTab.get(t) == 0) {
            if (arestas.get(t).size() != 0) {
                Line line = arestas.get(t).get(arestas.get(t).size() - 1);
                if (procurarVertice(line.getStartX(), line.getStartY())) {
                    line.setEndX(arg.getX());
                    line.setEndY(arg.getY());
                }
            }
        }
    }

    @FXML
    private void handlegerarLista(ActionEvent arg0) {
        if (nVertices.get(t) < 100) {
            gerarListaAdjacencia();
            String Aux = listaAdjacencia.get(t).returnGrafo();
            Platform.runLater(() -> console.appendText(Aux + "\n"));
            console.end();
            stringConsole.set(t, console.getText());
        } else {
            console.setText(stringConsole.get(t) + "Graph is to big to print!");
            console.end();
        }

    }

    @FXML
    private void handleGerarMatriz(ActionEvent arg0) {
        if (nVertices.get(t) < 100) {
            gerarMatrizAdjacencia();
            String Aux = matrizAdjacencia.get(t).returnGrafo(console, stringConsole, t);
            Platform.runLater(() -> console.appendText(Aux + "\n"));
            console.end();
            stringConsole.set(t, console.getText());
        } else {
            console.setText(stringConsole.get(t) + "Graph is to big to print!");
            console.end();
        }

    }

    private boolean procurarVertice(double pX, double pY) //verifica se existe vertice em determinada posi��o...
    {
        double cX = 0;
        double cY = 0;
        for (int i = 1; i <= nVertices.get(t); i++) {
            cX = vertices.get(t).get(i - 1).getLayoutX();
            cY = vertices.get(t).get(i - 1).getLayoutY();
            if ((cX + raio) > pX && (cX - raio) < pX) {
                if ((cY + raio) > pY && (cY - raio) < pY) {
                    return true;
                }
            }
        }
        return false;
    }

    private int getIndiceVertice(double pX, double pY) //pega o indice do vertice localizado em uma determinada coordenada...
    {
        double cX = 0;
        double cY = 0;
        if (vertices.get(t).isEmpty()) {
            return -1;
        }
        for (int i = nVertices.get(t); i >= 1; i--) {
            cX = vertices.get(t).get(i - 1).getLayoutX();
            cY = vertices.get(t).get(i - 1).getLayoutY();
            if (((cX + raio) > pX && (cX - raio) < pX) || cX == pX && cY == pY) {
                if (((cY + raio) > pY && (cY - raio) < pY) || cX == pX && cY == pY) {
                    return i - 1;
                }
            }
        }
        return -1;
    }

    private ArrayList<Line> getArestasChegando(Circle vertice) // retorna um array com as arestas que estao em um vertice(as que vao, e as que chagam...)
    {
        ArrayList<Line> arestasSaindo = new ArrayList<Line>();
        double cX = vertice.getLayoutX();
        double cY = vertice.getLayoutY();
        for (int i = 0; i < arestas.get(t).size(); i++) {
            if (arestas.get(t).get(i).getEndX() == cX && arestas.get(t).get(i).getEndY() == cY) {
                arestasSaindo.add(arestas.get(t).get(i));
            }
        }
        return arestasSaindo;
    }

    private ArrayList<Line> getArestasSaindo(Circle vertice) // retorna um array com as
    {
        ArrayList<Line> arestasDoVertice = new ArrayList<Line>();
        double cX = vertice.getLayoutX();
        double cY = vertice.getLayoutY();
        for (int i = 0; i < arestas.get(t).size(); i++) {
            if (arestas.get(t).get(i).getStartX() == cX && arestas.get(t).get(i).getStartY() == cY) {
                arestasDoVertice.add(arestas.get(t).get(i));
            }

        }
        return arestasDoVertice;
    }

    private void gerarListaAdjacencia() {

        listaAdjacencia.set(t, new GraphList(nVertices.get(t)));
        int a = 0;
        int b = 0;
        for (int i = 0; i < arestas.get(t).size(); i++) {
            a = getIndiceVertice(arestas.get(t).get(i).getStartX(), arestas.get(t).get(i).getStartY()) + 1;
            b = getIndiceVertice(arestas.get(t).get(i).getEndX(), arestas.get(t).get(i).getEndY()) + 1;
            listaAdjacencia.get(t).ligar(a, b);
            listaAdjacencia.get(t).ligar(b, a);

        }
    }

    private void gerarMatrizAdjacencia() {
        matrizAdjacencia.set(t, new Graph(nVertices.get(t)));
        int a = 0;
        int b = 0;
        for (int i = 0; i < arestas.get(t).size(); i++) {

            a = getIndiceVertice(arestas.get(t).get(i).getStartX(), arestas.get(t).get(i).getStartY()) + 1;
            b = getIndiceVertice(arestas.get(t).get(i).getEndX(), arestas.get(t).get(i).getEndY()) + 1;

            matrizAdjacencia.get(t).aresta(a, b, false);

        }
    }

    private void diminuirFonte(int fila, int tabExecuntando) {
        Platform.runLater(() -> listaLabel.get(tabExecuntando).get(fila).setFont(Font.font("", 10)));

    }

    private void imprimir(String textoFila, int tabExecutando, String textoAnterior) {
        if (tabPane.getTabs().get(tabExecutando).isSelected()) {
            Platform.runLater(() -> console.setText(textoAnterior + textoFila + "\n"));
            stringConsole.set(tabExecutando, textoAnterior + textoFila + "\n");
            console.end();
        } else {
            stringConsole.set(tabExecutando, textoAnterior + textoFila + "\n");
        }

    }

    private void colorir(int a, int tabExecuntando) {
        Platform.runLater(() -> this.vertices.get(tabExecuntando).get(a).setFill(Color.KHAKI));
    }

    private void recolorir(int a, int tabExecuntando) {
        Platform.runLater(() -> this.vertices.get(tabExecuntando).get(a).setFill(Color.color(0.9, 0.1, 0.1)));
    }

    private void toWhite(int tabExecuntando) {

        for (int i = 0; i < listacores.get(tabExecuntando).size(); i++) {

            ((Pane) tabPane.getTabs().get(tabExecuntando).getContent()).getChildren()
                    .remove(listacores.get(tabExecuntando).get(i));
        }
        listacores.get(tabExecuntando).clear();
    }

}
